/**
 * Copyright (C) 2017 - 2020 https://github.com/joewee
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bifrost.service.impl;

import com.bifrost.common.util.MD5Utils;
import com.bifrost.entity.Media;
import com.bifrost.exception.FormatException;
import com.bifrost.repository.MediaRepository;
import com.bifrost.service.FileService;
import com.bifrost.service.MediaService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;
import sun.awt.image.ImageFormatException;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author joewee
 * @version 1.0.0
 * @Date 2017/10/19 14:18
 */
@Service
public class MediaServiceImpl implements MediaService {
    Pattern pattern = Pattern.compile("[\\s\\\\/:\\*\\?\\\"<>\\|]");
    @Autowired
    MediaRepository mediaRepository;
    @Value("${upload.file.path:upload/}")
    private String uploadPath;
    @Value("${upload.image.max.size:#{1024000}}")
    private long maxSize;

    @Autowired
    private FileService fileService;

    private static final Logger LOGGER = LoggerFactory.getLogger(MediaServiceImpl.class);

    @Override
    public Media save(Media media) {
        return mediaRepository.save(media);
    }

    @Override
    public Media getMediaById(Long id) {
        return mediaRepository.findOne(id);
    }

    /**
     * 根据hash值获取文件
     *
     * @param hash
     * @return
     */
    @Override
    public Media findByHash(String hash) {
        Assert.hasText(hash, "Hash值不能为空");
        return mediaRepository.findFirstByHash(hash);
    }

    /**
     * 上传文件
     *
     * @param files
     * @return
     */
    @Override
    public List<Media> upload(MultipartFile[] files, String title, String tag, String altText) throws FormatException {
        List resultList = new ArrayList();
        try {
            for (MultipartFile file : files) {
                if (file != null) {
                    //获取Md5哈希值
                    Media media = null;
                    String hash = MD5Utils.md5(file.getBytes(), true);
                    String originalName = file.getOriginalFilename();
                    if (StringUtils.isBlank(originalName)) {
                        originalName = file.getName();
                    }
                    ImageInputStream imageInputStream = ImageIO.createImageInputStream(file.getInputStream());
                    Iterator<ImageReader> iterator = ImageIO.getImageReaders(imageInputStream);
                    if (!iterator.hasNext()) {
                        throw new FormatException("不是有效的图片格式");
                    }
                    ImageReader reader = iterator.next();
                    String suffixName = reader.getFormatName();
                    if (suffixName == null) {
                        throw new FormatException("不是有效的图片格式");
                    }
                    Media existedMedia = findByHash(hash);
                    if (existedMedia != null) {
                        media = existedMedia;
                        if (existedMedia.getUrl().equalsIgnoreCase(suffixName)) {
                            //后缀未发生改变
                            media = existedMedia;
                            resultList.add(media);
                            continue;
                        }
                    }
                    //不存在
                    if (StringUtils.isBlank(suffixName) || !isImageFormat(suffixName)) {
                        throw new FormatException("不是有效的图片格式");
                    }
                    String path = null;
                    Calendar calendar = Calendar.getInstance();
                    String dateString = String.format("%s/%d/%d/", tag.trim(), calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1);
                    String randomStr = hash;
                    if (!StringUtils.isEmpty(title)) {
                        Matcher matcher = pattern.matcher(title);
                        // 将匹配到的非法字符以空替换
                        title = matcher.replaceAll("");
                        randomStr = String.format("%s-%s", title.trim(), hash);
                    }
                    if (!uploadPath.endsWith(File.separator)) {
                        path = uploadPath + File.separator + dateString + randomStr + "." + suffixName;
                    } else {
                        path = uploadPath + dateString + randomStr + "." + suffixName;
                    }
                    File newFile = new File(path);
                    if (file.getSize() > maxSize) {
                        //Thumbnails.of(ImageIO.read(file.getInputStream())).scale(1f).outputQuality(0.25f).toFile(new File(path));
                        //ImageIO.write(image,suffixName,newFile);
                        FileUtils.writeByteArrayToFile(newFile, file.getBytes());
                    } else {
                        //ImageIO.getImageReaders(image);
                        //ImageIO.write(image,suffixName,newFile);
                        FileUtils.writeByteArrayToFile(newFile, file.getBytes());
                    }
                    if (!fileService.upload(newFile,dateString, true))//上传失败，跳过本次循环
                        continue;
                    if (media == null) {
                        media = new Media();
                        media.setHash(hash);
                        media.setSize(file.getSize());
                        try {
                            BufferedImage image = ImageIO.read(file.getInputStream());
                            if (image != null) {
                                media.setWidth(image.getWidth());
                                media.setHeight(image.getHeight());
                            }
                        } catch (Exception e) {
                            LOGGER.warn("获取图片高度、宽度失败：{}", e.getMessage());
                        }
                        if (StringUtils.isEmpty(altText)) {
                            media.setAltText(StringUtils.substringBeforeLast(originalName, "."));
                        } else {
                            media.setAltText(altText.trim());
                        }
                        if (StringUtils.isEmpty(title)) {
                            media.setTitle(StringUtils.substringBeforeLast(originalName, "."));
                        } else {
                            media.setTitle(title.trim());
                        }
                        media.setMediaTags(tag.trim());
                    }
                    media.setPath(path);
                   /* String contextPath = request.getContextPath();
                    if(StringUtils.isNotEmpty(contextPath)){
                        //StringUtils.remove(request.getRequestURL().toString(), request.getRequestURI()) +contextPath+
                        media.setUrl("/" + dateString + randomStr + "." + suffixName);
                    }else{*/
                    //StringUtils.remove(request.getRequestURL().toString(), request.getRequestURI()) +
                    media.setUrl("/" + dateString + randomStr + "." + suffixName);
                    // }
                    media = save(media);
                    resultList.add(media);
                }
            }
        } catch (IOException e) {
            LOGGER.error("上传图片失败", e);
        }
        return resultList;
    }

    @Override
    public void formatImage() {
        List<Media> medias = mediaRepository.findAll();
        if (CollectionUtils.isNotEmpty(medias)) {
            medias.forEach(media -> {
                String url = media.getUrl();
                String path = media.getPath();
                if (StringUtils.isNotBlank(path)) {
                    File file = new File(path);
                    if (file.exists()) {
                        ImageInputStream imageInputStream = null;
                        try {
                            imageInputStream = ImageIO.createImageInputStream(file);
                            Iterator<ImageReader> iterator = ImageIO.getImageReaders(imageInputStream);
                            if (iterator.hasNext()) {
                                ImageReader reader = iterator.next();
                                String suffixName = reader.getFormatName();
                                if (!url.endsWith("." + suffixName)) {
                                    media.setUrl(StringUtils.substringBeforeLast(url, ".") + suffixName);
                                    String newPath = StringUtils.substringBeforeLast(path, ".") + suffixName;
                                    media.setPath(newPath);
                                    mediaRepository.save(media);
                                    ImageIO.write(ImageIO.read(imageInputStream), suffixName, new File(newPath));
                                    file.delete();
                                }
                            }
                        } catch (Exception e) {
                            LOGGER.error(e.getMessage(), e);
                        }
                    }
                }
            });
        }
    }

    private boolean isImageFormat(String suffixName) {
        if (StringUtils.isBlank(suffixName)) {
            return false;
        }
        if ("png".equalsIgnoreCase(suffixName.trim()) || "jpg".equalsIgnoreCase(suffixName.trim()) || "gif".equalsIgnoreCase(suffixName.trim()) || "jpeg".equalsIgnoreCase(suffixName.trim())) {
            return true;
        } else {
            return false;
        }
    }

    private String readPictureType(MultipartFile file) throws IOException {
        byte[] buffer = Arrays.copyOf(file.getBytes(), 8);
        String fileType = null;
        if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F' && buffer[3] == '8' &&
                (buffer[4] == '7' || buffer[4] == '9') && buffer[5] == 'a') {
            fileType = "GIF";
        } else if ((buffer[0] == 0x42) && (buffer[1] == 0x4d)) {
            fileType = "BMP";
        } else if ((buffer[0] == (byte) 137 &&
                buffer[1] == (byte) 80 &&
                buffer[2] == (byte) 78 &&
                buffer[3] == (byte) 71 &&
                buffer[4] == (byte) 13 &&
                buffer[5] == (byte) 10 &&
                buffer[6] == (byte) 26 &&
                buffer[7] == (byte) 10)) {
            fileType = "PNG";
        } else if ((buffer[0] == 0xFF) && (buffer[1] == 0xd8)) {
            fileType = "JPEG";
        }
        return fileType;
    }
}
